package sf.database.template.enjoy.ext;

import com.jfinal.template.Directive;
import com.jfinal.template.Env;
import com.jfinal.template.TemplateException;
import com.jfinal.template.expr.ast.Expr;
import com.jfinal.template.io.Writer;
import com.jfinal.template.stat.Scope;
import sf.dsl.example.DSLMethod;

import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * 元组指令
 * #tuple(1,valueList) 或者 #tuple(1,valueArray)
 * 生成 (1,2,3,4) 或者 ((1,2),(3,4))
 * 参数1 为 列长度 大于1 会组内分组;参数2 为 值
 */
public class TupleDirective extends Directive {
    @Override
    public void exec(Env env, Scope scope, Writer writer) {
        SqlPara sqlPara = (SqlPara) scope.get(SqlKit.SQL_PARA_KEY);
        if (sqlPara == null) {
            throw new TemplateException("#tuple directive invoked by getSqlPara(...) method only", location);
        }
        if (exprList.length() == 2) {
            int splitSize = 0;
            Expr expr = exprList.getExpr(0);
            Object o = expr.eval(scope);
            if (o instanceof Number) {
                splitSize = ((Number) o).intValue();
            }
            Expr expr1 = exprList.getExpr(1);
            Object o1 = expr1.eval(scope);
            if (o1 != null) {
                List<Object> paraValues = new ArrayList<>();
                String str = tuple(splitSize, o1, paraValues);
                write(writer, str);
                for (Object v : paraValues) {
                    sqlPara.addPara(v);
                }
            }
        } else {
            throw new TemplateException("#tuple directive length must equal 2", location);
        }
    }

    public static String tuple(int splitSize, Object o, List<Object> paraValues) {
        String ret = "";
        if (o == null) {
            return ret;
        }
        StringBuilder sb = new StringBuilder();
        if (o instanceof Collection) {
            Collection<Object> values = (Collection<Object>) o;
            if (values.isEmpty()) {
                return ret;
            }
            int valueSize = values.size();
            sb.append("(");
            int useValueSize = DSLMethod.placeholderMultiple(sb, DSLMethod.getTupleCount(valueSize, splitSize), splitSize);
            int count = 0;
            for (Object val : values) {
                paraValues.add(val);
                count++;
                if (count >= useValueSize) {
                    break;
                }
            }
            sb.append(")");
        } else if (o.getClass().isArray()) {
            int valueSize = Array.getLength(o);
            if (valueSize == 0) {
                return ret;
            }
            sb.append("(");
            int useValueSize = DSLMethod.placeholderMultiple(sb, DSLMethod.getTupleCount(valueSize, splitSize), splitSize);
            for (int i = 0; i < useValueSize; i++) {
                Object val = Array.get(o, i);
                paraValues.add(val);
            }
            sb.append(")");
        } else {
            sb.append("(?)");
            paraValues.add(o);
        }
        ret = sb.toString();
        return ret;
    }
}
